package com.heima.article.service.impl;

import com.alibaba.fastjson.JSON;
import com.heima.article.mapper.ApArticleMapper;
import com.heima.article.service.ApArticleService;
import com.heima.article.service.HotArticleComputeService;
import com.heima.common.constants.ArticleConstants;
import com.heima.model.article.pojos.ApArticle;
import com.heima.model.article.vos.HotArticleVo;
import io.swagger.models.auth.In;
import lombok.extern.slf4j.Slf4j;
import org.apache.logging.log4j.core.pattern.IntegerPatternConverter;
import org.joda.time.DateTime;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.function.Predicate;
import java.util.stream.Collectors;

@Service
@Slf4j
public class HotArticleComputeServiceImpl implements HotArticleComputeService {

    @Autowired
    ApArticleMapper apArticleMapper;
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public void computeHotArticle() {
        //1.查询前5天内的文章
        //求前5天时间点是多少
        Date date = DateTime.now().minusDays(5).toDate();
        List<ApArticle> list = apArticleMapper.loadArticleListByDate(date);//查询近5天内发布的文章
        log.info("近5天发布的文章 {}", list.size());
        if(list==null || list.size()==0){
            //说明前5天内没有发布的文章
            log.info("近5天没有发布的文章");
            return;
        }


        //2.计算每一篇文章分值
        List<HotArticleVo> vos = computeArticleScore(list);
        for (HotArticleVo vo : vos) {
            log.info("计算分值后的文章对象:  {}", vo);
        }


        //3.为每个频道缓存分值较高的前30篇文章（推荐下也需要缓存值较高的前30篇文章，不区分频道）
        cacheTagToRedis(vos);

    }

    /**
     * 为每个频道缓存分值较高的前30篇文章（推荐下也需要缓存值较高的前30篇文章，不区分频道）
     * @param vos
     */
    private void cacheTagToRedis(List<HotArticleVo> vos) {
//        Set<Integer> channelIds = new HashSet<>();
//        for (HotArticleVo vo : vos) {
//            channelIds.add(vo.getChannelId());
//        }
        //获取所有频道的id 集合    1  2 3
        Set<Integer> channelIds = vos.stream().map(HotArticleVo::getChannelId).collect(Collectors.toSet());

        for (Integer channelId : channelIds) {
//            List<HotArticleVo> tmp = new ArrayList<>();
//            for (HotArticleVo vo : vos) {//循环所有文章
//                if(channelId.equals(vo.getChannelId())){
//                    tmp.add(vo);
//                }
//            }
            List<HotArticleVo> tmplist = vos.stream().filter(hotArticleVo -> channelId.equals(hotArticleVo.getChannelId())).collect(Collectors.toList());
            //以频道为维度    缓存到redis
            //hot_article_first_page_频道id
            sortScoreAndCacheRedis(tmplist, ArticleConstants.HOT_ARTICLE_FIRST_PAGE+channelId);//为每个频道缓存  该频道文章
        }
        //缓存推荐  频道下文章 到redis，推荐频道下，是包含所有频道下的文章
        //hot_article_first_page___all__  这就是推荐频道 在redis中的key
        sortScoreAndCacheRedis(vos, ArticleConstants.HOT_ARTICLE_FIRST_PAGE+ArticleConstants.DEFAULT_TAG);//为推荐频道缓存  所有文章
    }

    /**
     * 将文章集合tmpList   安装分值score属性降序   后取前30  缓存redis
     * @param tmplist  文章集合
     * @param key  redis中的key
     */
    private void sortScoreAndCacheRedis(List<HotArticleVo> tmplist, String key) {
        List<HotArticleVo> voList = tmplist
                .stream()
                .sorted(Comparator.comparing(HotArticleVo::getScore).reversed())//安装分值排序  默认是升序
                .limit(30)
                .collect(Collectors.toList());

        stringRedisTemplate.boundValueOps(key).set(JSON.toJSONString(voList));
    }

    /**
     * 针对list中的文章，计算每一篇文章分值 最后封装到HotArticleVo
     * @param list
     * @return
     */
    private List<HotArticleVo> computeArticleScore(List<ApArticle> list) {
        List<HotArticleVo> vos = new ArrayList<>();
        for (ApArticle article : list) {
            HotArticleVo vo = new HotArticleVo();
            BeanUtils.copyProperties(article, vo);
            //计算分值 赋值给vo的score属性
            Integer score = computeScore(vo);
            vo.setScore(score);
            vos.add(vo);
        }
        return vos;
    }

    /**
     * 计算文章分值
     * 阅读权重是1   点赞是3  评论是5   收藏是8
     * @param vo
     * @return
     */
    private Integer computeScore(HotArticleVo vo) {
        Integer score = 0;
        if(vo.getViews()!=null){
            score += vo.getViews().intValue() * ArticleConstants.HOT_ARTICLE_VIEW_WEIGHT;
        }
        if(vo.getLikes()!=null){
            score += vo.getLikes().intValue() * ArticleConstants.HOT_ARTICLE_LIKE_WEIGHT;
        }
        if(vo.getComment()!=null){
            score += vo.getComment().intValue() * ArticleConstants.HOT_ARTICLE_COMMENT_WEIGHT;
        }
        if(vo.getCollection()!=null){
            score += vo.getCollection().intValue() * ArticleConstants.HOT_ARTICLE_COLLECTION_WEIGHT;
        }
        return score;
    }
}
